package com.lib.common.helper.api.upload

import com.lib.common.entity.api.resp.Credentials
import com.lib.framework.manager.ContextManager
import com.lib.framework.manager.LogManager
import com.tencent.cos.xml.CosXmlService
import com.tencent.cos.xml.exception.CosXmlClientException
import com.tencent.cos.xml.exception.CosXmlServiceException
import com.tencent.cos.xml.model.bucket.ListMultiUploadsRequest
import com.tencent.cos.xml.model.tag.ListMultipartUploads
import com.tencent.cos.xml.transfer.COSXMLUploadTask
import com.tencent.cos.xml.transfer.TransferManager
import com.tencent.qcloud.core.auth.BasicLifecycleCredentialProvider
import com.tencent.qcloud.core.auth.QCloudLifecycleCredentials
import com.tencent.qcloud.core.auth.SessionQCloudCredentials

/**
 * 文 件 名: UploadHelper
 * 创 建 人: beyond
 * 创建日期: 2019-06-25 14:03
 * 邮   箱: beyond.wang@xiangwushuo.com
 * 文件功能：上传文件辅助类，支持断点续传和分片上传
 */
object UploadHelper {

    const val TAG = "upload"

    /**
     * 获得腾讯云上传任务
     */
    fun getCOSXMLUploadTask(credentials: Credentials, srcPath: String): COSXMLUploadTask {
        LogManager.i(TAG, "start upload\t$srcPath")
        var cosPath: String //cos上文件的位置
        var mUpload: ListMultipartUploads.Upload? = null //若UploadId不为空,则可以进行续传
        val cosXmlService = CosXmlService(
            ContextManager.applicationContext,
            QServiceCfg.instance().serviceConfig,
            ShareCredentialProvider(credentials)
        )
        //查询是否上传过
        QServiceCfg.instance().partPathList[srcPath]?.let {
            mUpload = getUploadId(it, cosXmlService)
        }
        cosPath = if (mUpload?.key == null) {
            QServiceCfg.instance().generateCosPath(srcPath)
        } else {
            LogManager.i(TAG, "continue upload\t$srcPath\t;cosPath is ${mUpload!!.key}")
            mUpload!!.key
        }
        LogManager.i(TAG, "upload $srcPath to cosPath->\t$cosPath")
        QServiceCfg.instance().setPartPath(srcPath, cosPath)

        return TransferManager(cosXmlService, QServiceCfg.instance().transferConfig).upload(
            QServiceCfg.BUCKET,
            cosPath,
            srcPath,
            mUpload?.uploadID
        )
    }


    /**
     *  续传 ： 根据uploadId 来完成 续传，因为 uploadId 唯一确定了 此 bucket 下面还有那些 object
     *  未有上传完成。
     *  步骤：
     *  step 1: 首先 列举 bucket下面 有哪些未上传完成 的 object, 调用 ListMultiUploadsRequest实现，并
     *  获取 到 ListMultiUploadsResult；
     *
     *  step2: 根据 ListMultiUploadsResult中的 ListMultipartUploads 中的 Upload 就可以 获取到对应的
     *  uploadId 和 key
     *
     *  step3: 根据 Key 做匹配，确实是否是这个 object
     *
     * 查询存储桶（Bucket）中正在进行中的分块上传对象的同步方法
     *
     * @param cosPath cos上文件的位置
     * @param cosXmlService
     */
    private fun getUploadId(
        cosPath: String,
        cosXmlService: CosXmlService
    ): ListMultipartUploads.Upload? {
        val listMultiUploadsRequest = ListMultiUploadsRequest(QServiceCfg.BUCKET)
        try {
            val listMultiUploadsResult = cosXmlService.listMultiUploads(listMultiUploadsRequest)
            listMultiUploadsResult?.listMultipartUploads?.uploads?.let {
                for (upload in it) {
                    LogManager.i(TAG, "uploadId->" + upload.uploadID + ";cosPath->" + upload.key)
                    if (upload.key == cosPath) {
                        LogManager.i(
                            TAG,
                            "exist upload->" + upload.uploadID + ";cosPath->" + upload.key
                        )
                        return upload
                    }
                }
            }
        } catch (e: CosXmlClientException) {
            LogManager.e(TAG, "QCloudException =" + e.message)
        } catch (e: CosXmlServiceException) {
            LogManager.e(TAG, "QCloudServiceException =$e")
        }
        return null
    }

    /**
     * 鉴权
     */
    class ShareCredentialProvider(private val credentials: Credentials) :
        BasicLifecycleCredentialProvider() {

        override fun fetchNewCredentials(): QCloudLifecycleCredentials {
            return SessionQCloudCredentials(
                credentials.credential?.tmpSecretId,
                credentials.credential?.tmpSecretKey, credentials.credential?.sessionToken,
                credentials.startTime ?: 0, credentials.expiredTime ?: 0
            )
        }
    }
}